package com.ithero.contentcenter.service.content;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ithero.contentcenter.dao.content.MidUserShareMapper;
import com.ithero.contentcenter.dao.content.ShareMapper;
import com.ithero.contentcenter.dao.messaging.RocketmqTransactionLogMapper;
import com.ithero.contentcenter.domain.dto.content.ShareAuditDTO;
import com.ithero.contentcenter.domain.dto.content.ShareDTO;
import com.ithero.contentcenter.domain.dto.messaging.UserAddBonusMsgDTO;
import com.ithero.contentcenter.domain.dto.user.UserAddBonseDTO;
import com.ithero.contentcenter.domain.dto.user.UserDTO;
import com.ithero.contentcenter.domain.entity.content.MidUserShare;
import com.ithero.contentcenter.domain.entity.content.Share;
import com.ithero.contentcenter.domain.entity.messaging.RocketmqTransactionLog;
import com.ithero.contentcenter.domain.enums.AuditStatusEnum;
import com.ithero.contentcenter.feignclient.UserCenterFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ShareService {

    @Autowired
    private ShareMapper shareMapper;

    @Autowired
    private RocketmqTransactionLogMapper rocketmqTransactionLogMapper;

    @Autowired
    private MidUserShareMapper midUserShareMapper;

    /*@Autowired
    private RestTemplate restTemplate;*/

    /*@Autowired
    private DiscoveryClient discoveryClient;*/

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private Source source;

    @Autowired
    private UserCenterFeignClient userCenterFeignClient;

    public ShareDTO findById(Integer id) {
        // 获取分享详情
        Share share = this.shareMapper.selectByPrimaryKey(id);

        // 发布人id
        Integer userId = share.getUserId();

        /*List<ServiceInstance> instances = this.discoveryClient.getInstances("user-center");
        List<String> targetURLs = instances.stream().map(instance -> instance.getUri().toString() + "/users/{userId}").collect(Collectors.toList());
        int i = ThreadLocalRandom.current().nextInt(targetURLs.size());
        log.info(targetURLs.get(i));*/

        // 调用用户微服务查询分享人信息
        // RestTemplate方式
        //UserDTO userDTO = this.restTemplate.getForObject("http://user-center/users/{userId}", UserDTO.class, userId);

        // feign方式
        UserDTO userDTO = userCenterFeignClient.findById(userId);

        // 消息装配
        ShareDTO shareDTO = new ShareDTO();
        BeanUtils.copyProperties(share, shareDTO);
        shareDTO.setWxNickName(userDTO.getWxNickname());

        return shareDTO;
    }

    public Share auditById(Integer id, ShareAuditDTO auditDTO) {
        // 1. 查询share是否存在，不存在或者当前的audit_status != NOT_YET，那么抛异常
        Share share = shareMapper.selectByPrimaryKey(id);
        if (share == null) {
            throw new IllegalArgumentException("参数非法！改分享不存在！");
        }
        if (Objects.equals(AuditStatusEnum.NOT_YET, share.getAuditStatus())) {
            throw new IllegalArgumentException("参数非法！改分享已经通过审核！");
        }

        // 2. 审核资源，将状态设为PASS/REJECT
        //auditByIdInDB(id, auditDTO);

        // 3. 如果是PASS，那么发送消息给rocketmq，将为发布人添加积分
        String transactionId = UUID.randomUUID().toString();
        if (AuditStatusEnum.PASS.equals(auditDTO.getAuditStatusEnum())) {

            // 使用stream编程模型
            this.source.output().send(
                    MessageBuilder.withPayload(
                            UserAddBonusMsgDTO.builder().userId(share.getUserId()).bonus(50).build()
                    )
                            .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                            .setHeader("share_id", id)
                            .setHeader("dto", JSON.toJSONString(auditDTO))
                            .build()
            );

            // 使用rocketmq发送事务消息
            //sendWithRocketMQTemplate(id, auditDTO, share, transactionId);

        } else {
            // 如果是REJECT，不需要发消息
            this.auditByIdInDB(id, auditDTO);
        }

        return share;
    }

    public void auditByIdInDB(Integer id, ShareAuditDTO auditDTO) {
        Share share = Share.builder()
                .id(id)
                .auditStatus(auditDTO.getAuditStatusEnum().toString())
                .reason(auditDTO.getReason())
                .build();

        shareMapper.updateByPrimaryKeySelective(share);

        // 把share写到缓存里
    }

    public void auditByIdWithRocketMQLog(Integer id, ShareAuditDTO shareAuditDTO, String transactionId) {

        this.auditByIdInDB(id, shareAuditDTO);

        this.rocketmqTransactionLogMapper.insertSelective(
                RocketmqTransactionLog.builder().transactionId(transactionId).log("审核分享...").build()
        );
    }

    private void sendWithRocketMQTemplate(Integer id, ShareAuditDTO auditDTO, Share share, String transactionId) {
        this.rocketMQTemplate.sendMessageInTransaction(
                "test-group",
                "add-bonus",
                MessageBuilder.withPayload(
                        UserAddBonusMsgDTO.builder().userId(share.getUserId()).bonus(50).build()
                )
                        .setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
                        .setHeader("share_id", id)
                        .build(),
                auditDTO
        );
    }

    public PageInfo<Share> q(String title, Integer pageNo, Integer pageSize, Integer userId) {
        // 分页
        PageHelper.startPage(pageNo, pageSize);

        List<Share> shares = this.shareMapper.selectByParam(title);
        List<Share> sharesDeal;
        // 1. 如果用户未登录
        if (userId == null) {
            sharesDeal = shares.stream()
                    .peek(share -> {
                        share.setDownloadUrl(null);
                    }).collect(Collectors.toList());
        } else {
            // 2. 如果用户登陆了，查询是否兑换过
            sharesDeal = shares.stream()
                    .peek(share -> {
                        MidUserShare midUserShare = midUserShareMapper.selectOne(
                                MidUserShare.builder().userId(userId).shareId(share.getId()).build()
                        );
                        if (midUserShare == null) {
                            share.setDownloadUrl(null);
                        }
                    }).collect(Collectors.toList());
        }
        return new PageInfo<>(sharesDeal);
    }

    public Share exchangeById(Integer id, HttpServletRequest request) {
        Integer userId = (Integer) request.getAttribute("id");

        // 1. 根据id查询share，校验是否存在
        Share share = this.shareMapper.selectByPrimaryKey(id);
        if (share == null) {
            throw new IllegalArgumentException("该分享不存在！");
        }
        Integer price = share.getPrice();
        MidUserShare midUserShare = this.midUserShareMapper.selectOne(
                MidUserShare.builder()
                        .userId(userId)
                        .shareId(id)
                        .build()
        );
        // 当前用户已经兑换过该分享，直接返回
        if (midUserShare != null) {
            return share;
        }

        // 2. 根据当前登录的用户id，查询积分是否足够
        UserDTO userDTO = this.userCenterFeignClient.findById(userId);
        if (price > userDTO.getBonus()) {
            throw new IllegalArgumentException("用户积分不够兑换！");
        }

        // 3. 扣减积分，往mid_user_share里插入一条数据
        this.userCenterFeignClient.addBonus(
                UserAddBonseDTO.builder()
                    .userId(userId)
                    .bonus(0 - price)
                    .build()
        );
        this.midUserShareMapper.insertSelective(
                MidUserShare.builder()
                    .userId(userId)
                    .shareId(id)
                    .build()
        );
        return share;
    }
}
